package com.expdatacloud.aop;

import com.alibaba.fastjson.JSON;
import com.expdatacloud.annotation.AutoLog;
import com.expdatacloud.entity.log.HandleLogBean;
import com.expdatacloud.service.LogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
 * 系统日志，切面处理类
 *
 * @author jie
 * @date 2019/12/23 -13:36
 */
@Aspect
@Component
public class AutoLogAspect {
    @Autowired
    private LogService logService;

    @Pointcut("@annotation(com.expdatacloud.annotation.AutoLog)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = null;
        long beginTime = System.currentTimeMillis();
        try {
            //执行方法
            result = point.proceed();

            //方法执行结束保存日志
            saveSysLog(point);
        }catch (Throwable e){
            saveSysErrorLog(point,e.toString());
            throw new RuntimeException(e);
        }
        
        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        assert servletRequestAttributes != null;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String user = request.getSession().getAttribute("users").toString();
        Object[] args = joinPoint.getArgs();
        String params = "";
        String method = request.getMethod();
        String queryString = request.getQueryString();

        if (args.length > 0) {
            if ("POST".equals(method) || "PUT".equals(method)) {
                Object object = args[0];
                Map map = getKeyAndValue(object);
                if (args[0] instanceof HttpServletRequest
                        || args[0] instanceof HttpServletResponse)
                {
                    params = null;
                }else {
                    params = JSON.toJSONString(map);
                }
            }else if("GET".equals(method) || "DELETE".equals(method)){
                params = queryString;
            }
        }

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method2 = signature.getMethod();
        AutoLog syslog = method2.getAnnotation(AutoLog.class);

        HandleLogBean handleLogBean = new HandleLogBean();
        handleLogBean.setTitle(syslog.title());
        handleLogBean.setAction(syslog.action());
        handleLogBean.setMethod(method2.getName());
        handleLogBean.setOperName(user);
        handleLogBean.setOperParam(params);
        handleLogBean.setErrorMsg(syslog.msg());
        //保存系统日志
        logService.info(handleLogBean);
    }

    private void saveSysErrorLog(ProceedingJoinPoint joinPoint, String errorMsg) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        assert servletRequestAttributes != null;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String user = request.getSession().getAttribute("users").toString();
        Object[] args = joinPoint.getArgs();
        String params = "";
        String method = request.getMethod();
        String queryString = request.getQueryString();

        if (args.length > 0) {
            if ("POST".equals(method) || "PUT".equals(method)) {
                Object object = args[0];
                Map map = getKeyAndValue(object);
                if (args[0] instanceof HttpServletRequest
                        || args[0] instanceof HttpServletResponse)
                {
                    params = null;
                }else {
                    params = JSON.toJSONString(map);
                }
            }else if("GET".equals(method) || "DELETE".equals(method)){
                params = queryString;
            }
        }

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method2 = signature.getMethod();
        AutoLog syslog = method2.getAnnotation(AutoLog.class);

        HandleLogBean handleLogBean = new HandleLogBean();
        handleLogBean.setTitle(syslog.title());
        handleLogBean.setAction(syslog.action());
        handleLogBean.setMethod(method2.getName());
        handleLogBean.setOperName(user);
        handleLogBean.setOperParam(params);
        handleLogBean.setErrorMsg(errorMsg);
        //保存系统日志
        logService.error(handleLogBean);
    }

    private static Map<String, Object> getKeyAndValue(Object object) {
        if (object == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        //得到类对象
        Class userCla = (Class) object.getClass();
        //得到类中的所有的集合
        Field[] declaredFields = userCla.getDeclaredFields();
        for (int i = 0; i < declaredFields.length; i++) {
            Field f = declaredFields[i];
            f.setAccessible(true);
            Object val = new Object();
            try {
                val = f.get(object);
                //得到属性的值
                map.put(f.getName(), val);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

}
